package com.qfedu.scode.util;

import com.qfedu.scode.dto.DbConfigDto;
import com.qfedu.scode.dto.ProjectConfigDto;
import com.qfedu.scode.dto.TbFieldDto;
import org.beetl.core.Configuration;
import org.beetl.core.GroupTemplate;
import org.beetl.core.Template;
import org.beetl.core.resource.ClasspathResourceLoader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @program: StartCoding
 * @description:
 * @author: Feri(邢朋辉)
 * @create: 2021-01-05 14:15
 */
public class JdbcUtil {
    public static final String CODE_DIR="gencode";
    public static final String[] CODE_PACKAGE={"entity","dao","mapper","vo","service/intf","service/impl","controller","config"};
    public static void main(String[] args) throws IOException {
        DbConfigDto dbConfigDto=new DbConfigDto();
        dbConfigDto.setDbname("java208");
        dbConfigDto.setHost("www.buildup.vip");
        dbConfigDto.setPort(3306);
        dbConfigDto.setUsername("root");
        dbConfigDto.setPass("199795.Cq");
        ProjectConfigDto configDto=new ProjectConfigDto();
        configDto.setAuthor("蔡强");
        configDto.setDesc("自动生成器");
        configDto.setPkname("com.caiqiang.test");
        configDto.setPname("CqTest");
        createJava(configDto,dbConfigDto);
    }
    /**
     * 实现数据库表的信息的获取*/
    public static Map<String, Map<String,String>> readInfo(DbConfigDto dto){
        Map<String, Map<String,String>> map=new LinkedHashMap<>();
        try {
            //1.加载驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            //2.获取连接
            Connection connection= DriverManager.getConnection("jdbc:mysql://"+dto.getHost()+":"+dto.getPort()+"/"+dto.getDbname()+"?serverTimezone=Asia/Shanghai",dto.getUsername(),dto.getPass());
            //3.获取元数据
            DatabaseMetaData metaData=connection.getMetaData();
            //4.获取表信息
            String[] types={"TABLE"};
            ResultSet set=metaData.getTables(dto.getDbname(),dto.getUsername(),null,types);
            Statement statement=connection.createStatement();
            //遍历获取表的信息
            while (set.next()){
                //获取表名
                String tname=set.getString("TABLE_NAME");
                LinkedHashMap<String,String> fields=new LinkedHashMap<>();
                map.put(tname,fields);
                //获取查询结果 查询对象
                ResultSet rs=statement.executeQuery("select * from "+tname+" limit 1");
                //表的元数据信息
                ResultSetMetaData rsMetaData=rs.getMetaData();
                int c=rsMetaData.getColumnCount();
                for(int i=1;i<=c;i++){
                    fields.put(rsMetaData.getColumnName(i),rsMetaData.getColumnTypeName(i));
                }
            }
            return map;
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
        return null;
    }
    //类型转换器
    public static String parseType(String type){
        String t;
        switch (type){
            case "TINYINT":
            case "SMALLINT":
            case "INTEGER":
            case "INT":
            case "BIT":  t="Integer";break;
            case "DECIMAL":
            case "BIGINT":
            case "FLOAT":
            case "DOUBLE":  t="Double";break;
            case "DATE":
            case "TIMESTAMP":
            case "TIME":  t="Date";break;
            default:t="String";break;

//            case "CHAR":
//            case "VARCHAR":
//            case "NCHAR":
//            case "NVARCHAR":
//            case "LONGNVARCHAR":
//            case "LONGVARCHAR":  t="String";break;

        }
        return t;
    }
    //表名-类名的转换
    private static String parseTableName(String name){
        if(name!=null && name.length()>0){
            if(name.length()==1){
                return name.toUpperCase();
            }else {
                if(name.contains("_")){
                    String[] arr=name.split("_");
                    if(arr!=null && arr.length>0){
                        StringBuffer buffer=new StringBuffer();
                        for(String s:arr){
                            if(s.equals("T") || s.equals("t")){
                                continue;
                            }else if(s.matches("^[a-zA-Z]{1,}")){
                                buffer.append(s.substring(0,1).toUpperCase()+s.substring(1).toLowerCase());
                            }
                        }
                        return buffer.toString();
                    }
                }else {
                    return name.substring(0,1).toUpperCase()+name.substring(1).toLowerCase();
                }
            }
        }
        return null;
    }
    //大驼峰式-小驼峰式
    private static String parseParamName(String name){
        if(name!=null && name.length()>0) {
            return name.substring(0, 1).toLowerCase() + name.substring(1);
        }else {
            return null;
        }
    }
    //把包转换为路径
    public static String createDir(String pkname){
        //com.qfedu.code.entity
        File rootDir=new File(CODE_DIR+"/"+pkname.replaceAll("\\.","/"));
        if(!rootDir.exists()){
          rootDir.mkdirs();
        }
        //根据分层创建对应的文件夹
        for(String s:CODE_PACKAGE){
            File child=new File(rootDir,s);
            if(!child.exists()){
                child.mkdirs();
            }
        }
        return rootDir.getPath();
    }
    //获取当前时间
    public static String getTime(){
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
    }
    //根据模板生成Java源文件
    public static void createJava(ProjectConfigDto configDto, DbConfigDto dbConfigDto){
        //读取数据库的内容
        Map<String, Map<String,String>> map=readInfo(dbConfigDto);
        //加载模板 8个 挨个生成
        //包-路径
        String baseDir=createDir(configDto.getPkname());
        //实例化Beetl的加载器
        ClasspathResourceLoader loader=new ClasspathResourceLoader("btl/");
        try{
            GroupTemplate groupTemplate=new GroupTemplate(loader, Configuration.defaultConfiguration());
            for(String clz:map.keySet()){
                StringBuffer bufferInsert=new StringBuffer();
                StringBuffer bufferAll=new StringBuffer();
                String entityName=parseTableName(clz);
                if(entityName!=null && entityName.length()>0) {
                    //实现实体层的源码
                    Template entity = groupTemplate.getTemplate("/EntityTem.btl");
                    Map<String, Object> entityMap = new LinkedHashMap<>();
                    entityMap.put("entitypkname", configDto.getPkname() + ".entity");
                    entityMap.put("projectname", configDto.getPname());
                    entityMap.put("projectdes", configDto.getDesc());
                    entityMap.put("author", configDto.getAuthor());
                    entityMap.put("entityname", entityName);
                    entityMap.put("projecttime", getTime());
                    ArrayList<TbFieldDto> list = new ArrayList<>();
                    Map<String, String> fields = map.get(clz);
                    bufferInsert.append("insert into " + clz + "(");
                    StringBuffer bufferValues = new StringBuffer();
                    for (String f : fields.keySet()) {
                        list.add(new TbFieldDto(f, parseType(fields.get(f))));
                        bufferInsert.append(f + ",");
                        bufferValues.append("#{" + f + "},");
                    }
                    bufferInsert.deleteCharAt(bufferInsert.length() - 1);
                    bufferInsert.append(") values(");
                    bufferValues.deleteCharAt(bufferValues.length() - 1);
                    bufferInsert.append(bufferValues + ")");
                    bufferAll.append("select * from " + clz);

                    entityMap.put("fields", list);
                    entity.binding(entityMap);
                    entity.renderTo(new FileOutputStream(baseDir + "/entity/" + entityMap.get("entityname") + ".java"));
                    //实现持久层的源码
                    Template dao = groupTemplate.getTemplate("/EntityDaoTem.btl");
                    Map<String, Object> daoMap = new LinkedHashMap<>();
                    daoMap.put("daopkname", configDto.getPkname() + ".dao");
                    daoMap.put("entitypkname", entityMap.get("entitypkname")+"."+entityName);
                    daoMap.put("projectname", configDto.getPname());
                    daoMap.put("projectdes", configDto.getDesc());
                    daoMap.put("author", configDto.getAuthor());
                    daoMap.put("projecttime", getTime());
                    daoMap.put("daoname", entityMap.get("entityname") + "Dao");
                    daoMap.put("entityname", entityMap.get("entityname"));
                    daoMap.put("eparamname", parseParamName(entityMap.get("entityname").toString()));

                    dao.binding(daoMap);
                    dao.renderTo(new FileOutputStream(baseDir + "/dao/" + daoMap.get("daoname")+".java"));

                    //实现持久映射文件层的源码
                    Template mapper = groupTemplate.getTemplate("/EntityMapperTem.btl");
                    Map<String, Object> mapperMap = new LinkedHashMap<>();
                    mapperMap.put("daopkname", configDto.getPkname() + ".dao." + daoMap.get("daoname"));
                    mapperMap.put("entityname", entityMap.get("entitypkname") + "." + entityMap.get("entityname"));
                    mapperMap.put("insertsql", bufferInsert.toString());
                    mapperMap.put("selectsql", bufferAll.toString());
                    mapper.binding(mapperMap);
                    mapper.renderTo(new FileOutputStream(baseDir + "/mapper/" + entityMap.get("entityname") + "Mapper.xml"));

                    //实现业务接口层的源码
                    Template serviceIntf = groupTemplate.getTemplate("/EntityServiceTem.btl");
                    Map<String, Object> serviceIntfMap = new LinkedHashMap<>();
                    serviceIntfMap.put("servicepkname", configDto.getPkname() + ".service.intf");
                    serviceIntfMap.put("entitypkname", entityMap.get("entitypkname") + "." + entityMap.get("entityname"));
                    serviceIntfMap.put("rpkname", configDto.getPkname()+".vo.R");
                    serviceIntfMap.put("projectname", configDto.getPname());
                    serviceIntfMap.put("projectdes", configDto.getDesc());
                    serviceIntfMap.put("author", configDto.getAuthor());
                    serviceIntfMap.put("projecttime", getTime());
                    serviceIntfMap.put("servicename", entityMap.get("entityname")+"Service");
                    serviceIntfMap.put("entityname", entityMap.get("entityname"));
                    serviceIntfMap.put("eparamname", daoMap.get("eparamname"));
                    serviceIntf.binding(serviceIntfMap);
                    serviceIntf.renderTo(new FileOutputStream(baseDir + "/service/intf/" + entityMap.get("entityname") + "Service.java"));
                    //实现业务实现层的源码
                    Template serviceImpl = groupTemplate.getTemplate("/EntityServiceImplTem.btl");
                    Map<String, Object> serviceImplMap = new LinkedHashMap<>();
                    serviceImplMap.put("serviceimplpkname", configDto.getPkname() + ".service.impl");
                    serviceImplMap.put("entitypkname", entityMap.get("entitypkname") + "." + entityMap.get("entityname"));
                    serviceImplMap.put("daopkname", daoMap.get("daopkname") + "." + daoMap.get("daoname"));
                    serviceImplMap.put("servicepkname", serviceIntfMap.get("servicepkname") + "." + serviceIntfMap.get("servicename"));
                    serviceImplMap.put("rpkname", configDto.getPkname()+".vo.R");
                    serviceImplMap.put("projectname", configDto.getPname());
                    serviceImplMap.put("projectdes", configDto.getDesc());
                    serviceImplMap.put("author", configDto.getAuthor());
                    serviceImplMap.put("projecttime", getTime());
                    serviceImplMap.put("serviceimplname", entityMap.get("entityname")+"ServiceImpl");
                    serviceImplMap.put("servicename", serviceIntfMap.get("servicename"));
                    serviceImplMap.put("daoname", daoMap.get("daoname"));
                    serviceImplMap.put("entityname", entityMap.get("entityname"));
                    serviceImplMap.put("eparamname", daoMap.get("eparamname"));
                    serviceImpl.binding(serviceImplMap);
                    serviceImpl.renderTo(new FileOutputStream(baseDir + "/service/impl/" + entityMap.get("entityname") + "ServiceImpl.java"));

                    //实现控制层的源码
                    Template controller = groupTemplate.getTemplate("/EntityControllerTem.btl");
                    Map<String, Object> controllerMap = new LinkedHashMap<>();
                    controllerMap.put("controllerpkname", configDto.getPkname() + ".controller");
                    controllerMap.put("entitypkname", entityMap.get("entitypkname") + "." + entityMap.get("entityname"));
                    controllerMap.put("servicepkname", serviceImplMap.get("servicepkname"));
                    controllerMap.put("rpkname", configDto.getPkname()+".vo.R");
                    controllerMap.put("projectname", configDto.getPname());
                    controllerMap.put("projectdes", configDto.getDesc());
                    controllerMap.put("author", configDto.getAuthor());
                    controllerMap.put("projecttime", getTime());
                    controllerMap.put("apiurl", "api/"+daoMap.get("eparamname")+"/");
                    controllerMap.put("apides", "实现"+entityMap.get("entityname")+"各种操作");
                    controllerMap.put("controllername", entityMap.get("entityname")+"Controller");
                    controllerMap.put("servicename", entityMap.get("entityname")+"Service");
                    controllerMap.put("entityname", entityMap.get("entityname"));
                    controllerMap.put("eparamname", daoMap.get("eparamname"));
                    controller.binding(controllerMap);
                    controller.renderTo(new FileOutputStream(baseDir + "/controller/" + entityMap.get("entityname") + "Controller.java"));

                    //实现R的源码
                    Template r = groupTemplate.getTemplate("/RTem.btl");
                    Map<String, Object> rMap = new LinkedHashMap<>();
                    rMap.put("vopkname", configDto.getPkname() + ".vo");
                    rMap.put("projectname", configDto.getPname());
                    rMap.put("projectdes", configDto.getDesc());
                    rMap.put("author", configDto.getAuthor());
                    rMap.put("projecttime", getTime());
                    r.binding(rMap);
                    r.renderTo(new FileOutputStream(baseDir + "/vo/R.java"));

                    //实现Swagger的源码
                    Template swagger = groupTemplate.getTemplate("/SwaggerTem.btl");
                    Map<String, Object> swaggerMap = new LinkedHashMap<>();
                    swaggerMap.put("configpkname", configDto.getPkname() + ".config");
                    swaggerMap.put("projectname", configDto.getPname());
                    swaggerMap.put("projectdes", configDto.getDesc());
                    swaggerMap.put("author", configDto.getAuthor());
                    swaggerMap.put("projecttime", getTime());
                    swaggerMap.put("controllerpkname", controllerMap.get("controllerpkname"));
                    swagger.binding(swaggerMap);
                    swagger.renderTo(new FileOutputStream(baseDir + "/config/SwaggerConfig.java"));
                }
            }
            //生成压缩文件
            //上传OSS
            //返回OSS路径
        }catch (IOException e){
            //递归删除已经生成的

        }

    }
}
